home *** CD-ROM | disk | FTP | other *** search
/ FM Towns: Free Software Collection 10 / FM Towns Free Software Collection 10.iso / ms_dos / tool / mercury / textview.c < prev    next >
Text File  |  1995-02-05  |  16KB  |  706 lines

  1. /*
  2.  
  3. MercuryInstaller テキストビュワールーチン
  4.  
  5. */
  6.  
  7. #include<stdio.h>
  8. #include<stdlib.h>
  9. #include<jctype.h>
  10. #include<string.h>
  11. #include<jstring.h>
  12. #include<farstr.h>
  13. #include<dos.h>
  14. #include<stdarg.h>
  15.  
  16. #include<LHACCESS.H>
  17. #include"mercury.h"
  18. /*===========================================================================*/
  19. /*                                 定数と変数                                */
  20. /*===========================================================================*/
  21. #define    TEXT_STARTYPOS    3    /* テキスト表示開始位置 */
  22. #define    TEXT_YWIDTH    (CON_YWIDTH-TEXT_STARTYPOS)
  23.             /* テキスト表示行数(putmessage専用行は除いてある) */
  24.  
  25. static    char    far    **Text;        /* テキストバッファ             */
  26. static    int        Linenum;    /* テキストの総行数             */
  27. static    int        Linepos;    /* 現在表示中の内容の開始行番号 */
  28. static    int        Bufsize;    /* バッファの行数               */
  29. /*===========================================================================*/
  30. /*                            ファイル読み込み関連                           */
  31. /*===========================================================================*/
  32.  
  33. /*------------------------------メモリの確保---------------------------------*/
  34. /* まず指定容量のメモリの確保を試み、失敗した場合は少しずつ容量を減らしてゆく*/
  35. /*---------------------------------------------------------------------------*/
  36. static    void    *nearcalloc_down(size_t num,size_t width,size_t *ret)
  37. {
  38.     void    *p;
  39.  
  40.     while    ((p=calloc(num,width))==NULL && num>1)
  41.         num--;
  42.  
  43.     if    (p==NULL)
  44.         *ret = 0;
  45.     else
  46.         *ret = num;
  47.  
  48.     return p;
  49. }
  50.  
  51. static void far *maxfarmalloc(long *size)
  52. {
  53.     long        s = farcoreleft();
  54.     void    far    *p;
  55.  
  56.     do
  57.     {
  58.         p = farmalloc(s);
  59.         if    (p!=NULL)
  60.         {
  61.             *size = s;
  62.             return p;
  63.         }
  64.     } while(--s);
  65.  
  66.     return NULL;
  67. }
  68.  
  69. /*-----------------------------仮想ファイルの処理----------------------------*/
  70. /* LHACCESSライブラリを経由した書庫ファイルか、それとも単なるベタテキストかを*/
  71. /* 全く意識せずに使用するためのルーチン                                      */
  72. /*---------------------------------------------------------------------------*/
  73. static    struct
  74. {
  75.     enum    {NONE,LZH,TEXT}    mode;
  76.     union
  77.     {
  78.         FILE    *fp;
  79.         ROOT    root;
  80.     } pointer;
  81. } File;
  82.  
  83. static    int    File_ungetc;
  84.  
  85. static    void    file_open(char *filename)
  86. {
  87.     char    *p = jstrchr(filename,'|');
  88.  
  89.     File_ungetc = EOF;
  90.  
  91.     if    (p!=NULL)    /* 書庫ファイルを通したアクセス */
  92.     {
  93.         *p = '\0';
  94.  
  95.         if    (islzh(filename)!=0 || 
  96.                 open_root(filename,&File.pointer.root)!=0)
  97.         {
  98.             *p = '|';
  99.             goto error;
  100.         }
  101.  
  102.         *p = '|';
  103.  
  104.         if    (get_all_header(&File.pointer.root)!=0 || 
  105.              lzh_fopen2(&File.pointer.root,p+1)!=0 )
  106.         {
  107.             close_root(&File.pointer.root);
  108.             goto error;
  109.         }
  110.  
  111.         File.mode = LZH;
  112.         return;
  113.     }
  114.     else
  115.     {
  116.         if    ((File.pointer.fp=fopen(filename,"r"))==NULL)
  117.             goto error;
  118.  
  119.         File.mode = TEXT;
  120.         return;
  121.     }
  122. error:
  123.     File.mode = NONE;
  124.     return;
  125. }
  126.  
  127. static    void    file_close(void)
  128. {
  129.     switch    (File.mode)
  130.     {
  131.     case LZH:
  132.         close_root(&File.pointer.root);
  133.         break;
  134.     case TEXT:
  135.         fclose(File.pointer.fp);
  136.         break;
  137.     }
  138. }
  139.  
  140. static    int    file_getc(void)
  141. {
  142.     int        c;
  143.  
  144.     if    (File_ungetc!=EOF)
  145.     {
  146.         c = File_ungetc;
  147.         File_ungetc = EOF;
  148.         return c;
  149.     }
  150.     switch    (File.mode)
  151.     {
  152.     case NONE:
  153.         return EOF;
  154.  
  155.     case LZH:
  156.         do
  157.             c = lzh_fgetc();
  158.         while    (c=='\r' || c=='\x1a');
  159.  
  160.         return c;
  161.  
  162.     case TEXT:
  163.         return fgetc(File.pointer.fp);
  164.     }
  165. }
  166.  
  167. #define    file_ungetc(c) (File_ungetc=(c))
  168. /*---------------------------テキストの読み込み------------------------------*/
  169. static    bool    readfile(char *filename)
  170. {
  171.     char far *p;
  172.     int    xlen=0;
  173.     int    c;
  174.     int    isknj = 0;
  175.     long    bufsize,buf_left;
  176.  
  177.     file_open(filename);
  178.  
  179.     Linenum = 0;
  180.  
  181.     Text = nearcalloc_down(4096,sizeof(char far *),&Bufsize);
  182.     if    (Text==NULL)
  183.     {
  184.         putmessage("メモリ不足です");
  185.         return 0;
  186.     }
  187.  
  188.     p = Text[0] = maxfarmalloc(&bufsize);
  189.     buf_left = bufsize;
  190.  
  191.     while    ((c=file_getc())!=EOF)
  192.     {
  193.         *p++ = c;
  194.         buf_left--;
  195.  
  196.         if    (c=='\t')
  197.             xlen += CON_TABSIZE - xlen%CON_TABSIZE;
  198.         else
  199.             xlen++;
  200.  
  201.         if    (!isknj && iskanji(c))
  202.             isknj = 1;
  203.         else
  204.             isknj = 0;
  205.  
  206.         if    (xlen>=CON_XWIDTH || c=='\n')
  207.         {
  208.             if    (isknj)
  209.             {
  210.                 file_ungetc(c);
  211.                 p--;
  212.                 buf_left++;
  213.                 isknj = 0;
  214.             }
  215.  
  216.             *p = '\0';
  217.             xlen = 0;
  218.  
  219.             if    (++Linenum == Bufsize)
  220.             {
  221.                 putmessage("行数が多すぎるので途中で打ち切ります");
  222.                 break;
  223.             }
  224.  
  225.             p += 1L;
  226.             Text[Linenum] = p;
  227.             buf_left--;
  228.         }
  229.  
  230.         if    (buf_left<2)
  231.         {
  232.             putmessage("メモリ不足です 途中で打ち切ります;bufsize=%ld,buf_left=%ld",bufsize,buf_left);
  233.             break;
  234.         }
  235.     }
  236.  
  237.     if    (xlen)
  238.     {
  239.         *p = '\0';
  240.         Linenum++;
  241.     }
  242.  
  243.     if    (Linenum==0)
  244.     {
  245.         farfree(Text[0]);
  246.         free(Text);
  247.     }
  248.     else
  249.     {
  250.         farrealloc(Text[0],bufsize-buf_left);
  251.         realloc(Text,Linenum*sizeof(Text[0]));
  252.     }
  253.     file_close();
  254.     return 1;
  255. }
  256. /*--------------------------ファイルバッファの解放---------------------------*/
  257. static    void    memory_release(void)
  258. {
  259.     if    (Linenum>0)
  260.     {
  261.         farfree(Text[0]);
  262.         free(Text);
  263.     }
  264. }
  265. /*-----------------------------パス名の生成----------------------------------*/
  266. static    void    mkpath(char *buf,char far *dir,char far *filename)
  267. {
  268.     if    (dir==NULL || filename[1]==':')
  269.         buf[0] = '\0';
  270.     else
  271.     {
  272.         buf[0] = Drive;
  273.         buf[1] = ':';
  274.         if    (filename[0]!='\\')
  275.         {
  276.             if    (dir!=NULL)
  277.                 far_strcpy(buf+2,dir);
  278.             else
  279.                 buf[2] = '\0';
  280.  
  281.             strcat(buf,"\\");
  282.         }
  283.         else
  284.             buf[2] = '\0';
  285.     }
  286.  
  287.     far_strcat(buf,filename);
  288. }
  289. /*-----------------------------ファイルの検索--------------------------------*/
  290. /* ○指定されたディレクトリからファイルを検索し、最初に見つかったファイルの  */
  291. /*  ファイル名をbufに返す。                                                 */
  292. /* ○ファイルが見つからない場合は、bufに空文字列をセットする。               */
  293. /* ○なお、dirはDataから引っ張ってくる関係でfarポインタになっている。        */
  294. /*---------------------------------------------------------------------------*/
  295. static    bool    findfile(char far *dir,char *wildcard,char buf[])
  296. {
  297.     char        *p;
  298.     struct    find_t    fib;
  299.  
  300.     mkpath(buf,dir,wildcard);
  301.  
  302.     if    ((p=jstrrchr(buf,'\\'))!=NULL)
  303.         p++;
  304.     else if    (buf[1]==':')
  305.         p = buf+2;
  306.     else
  307.         p = buf;
  308.  
  309.     if    (_dos_findfirst(buf,_A_NORMAL,&fib)==0)
  310.     {
  311.         strcpy(p,fib.name);
  312.         return 1;
  313.     }
  314.     else
  315.     {
  316.         buf[0] = '\0';
  317.         return 0;
  318.     }
  319. }
  320.  
  321. /*===========================================================================*/
  322. /*                     画面表示関連(1):テキストのスクロール                  */
  323. /*===========================================================================*/
  324.  
  325. /*----------------------------------行を表示---------------------------------*/
  326. static    void    showoneline(int ypos)
  327. {
  328.     printf("\033[%d;1f\033[2K",ypos+TEXT_STARTYPOS);
  329.  
  330.     if    (Linepos+ypos>=Linenum)
  331.         return;
  332.  
  333.     far_fputs(Text[Linepos+ypos],stdout);
  334. }
  335. /*---------------------画面全体の表示(インライン関数)------------------------*/
  336. #define    showtext() do                \
  337. {                        \
  338.     int    i;                \
  339.                         \
  340.     for    (i=0 ; i<TEXT_YWIDTH ; i++)    \
  341.         showoneline(i);            \
  342. } while(0)
  343. /*-------------------------------画面の初期化--------------------------------*/
  344. static    void    screen_init(char far *title,char *filename)
  345. {
  346.     static    char far *title_save;
  347.     static    char    *filename_save;
  348.     char    buf[TITLEWIDTH+1];
  349.  
  350.     if    (title==NULL)
  351.         title = title_save;
  352.     else
  353.         title_save = title;
  354.  
  355.     if    (filename==NULL)
  356.         filename = filename_save;
  357.     else
  358.         filename_save = filename;
  359.  
  360.     far_strcpy(buf,title);
  361.     printf("\033[2J\033[7;36m%-*s\033[37;7m%-*s\n",TITLEWIDTH,buf,
  362.                     CON_XWIDTH-TITLEWIDTH,"    [F5]HELP");
  363.     printf("\033[2;1f\033[7;36m%-*s\033[0m",CON_XWIDTH,filename);
  364.  
  365.     showtext();
  366. }
  367. /*-----------------------------画面のスクロール------------------------------*/
  368. static    void    scrolldown(void)
  369. {
  370.     if    (Linepos==Linenum-1)
  371.         return;
  372.  
  373.     Linepos++;
  374.  
  375.     printf("\033[%d;1f",TEXT_STARTYPOS);
  376.  
  377.     if    (Flag_isfmesc)    printf("\033R");
  378.     else            printf("\033[M");
  379.  
  380.     showoneline(TEXT_YWIDTH-1);
  381. }
  382.  
  383. static    void    scrollup(void)
  384. {
  385.     if    (Linepos==0)
  386.         return;
  387.  
  388.     Linepos--;
  389.  
  390.     printf("\033[%d;1f",TEXT_STARTYPOS);
  391.  
  392.     if    (Flag_isfmesc)    printf("\033E");
  393.     else            printf("\033[L");
  394.  
  395.     printf("\033[%d;1f\033[2K",TEXT_STARTYPOS+TEXT_YWIDTH);
  396.  
  397.     showoneline(0);
  398. }
  399.  
  400. /*===========================================================================*/
  401. /*               画面表示関連(2):ウィンドウシステムライブラリ                */
  402. /*===========================================================================*/
  403. /* これらの関数はtextviewer()の下でしか使えないので要注意。                  */
  404. /*===========================================================================*/
  405.  
  406. static    struct
  407. {
  408.     int    xstart,ystart;    /* 文字表示開始xy座標 */
  409.     int    xsize,ysize;    /* ウィンドウのサイズ */
  410. } Window;
  411.  
  412. /*-----------------------------ウィンドウを開く------------------------------*/
  413. extern    void    openwindow(int ysize,int xsize)
  414. {
  415.     int    i;
  416.  
  417.     Window.ysize = ysize;
  418.     Window.xsize = xsize;
  419.  
  420.     Window.xstart = (CON_XWIDTH-xsize)/2;
  421.     Window.ystart = (CON_YWIDTH-ysize)/2;
  422.  
  423.     printf("\033[%d;%df\033[36m+",Window.ystart-1,Window.xstart-1);
  424.     for    (i=0 ; i<Window.xsize ; i++)
  425.         putchar('-');
  426.  
  427.     printf("+\033[%d;%df+",Window.ystart+Window.ysize,Window.xstart-1);
  428.     for    (i=0 ; i<Window.xsize ; i++)
  429.         putchar('-');
  430.  
  431.     putchar('+');
  432.  
  433.     for    (i=0 ; i<Window.ysize ; i++)
  434.     {
  435.         printf("\033[%d;%df|%*s|",Window.ystart+i,Window.xstart-1,
  436.                             Window.xsize,"");
  437.     }
  438.  
  439.     printf("\033[0m");
  440. }
  441. /*----------------------------ウィンドウを閉じる-----------------------------*/
  442. extern    void    closewindow(void)
  443. {
  444.     int    i;
  445.  
  446.     for    (i=-1 ; i<=Window.ysize ; i++)
  447.         showoneline(Window.ystart+i-TEXT_STARTYPOS);
  448. }
  449. /*--------------------------------文字列の出力-------------------------------*/
  450. /* ウィンドウの各行の最後の1バイトは全角文字の禁則処理専用に予約済。         */
  451. /*---------------------------------------------------------------------------*/
  452. extern    void    window_putstr(int ypos,char *format,...)
  453. {
  454.     va_list    ap;
  455.     char    buf[256];
  456.     char    *p = buf;
  457.     char    c;
  458.     int    xpos = 0;
  459.  
  460.     va_start(ap,format);
  461.     vsprintf(buf,format,ap);
  462.  
  463.     while    ((c=*p++)!='\0')
  464.     {
  465.         if    (xpos==0)
  466.             printf("\033[%d;%df%*s\033[%d;%df",
  467.                     Window.ystart+ypos,Window.xstart,
  468.                     Window.xsize,"",
  469.                     Window.ystart+ypos,Window.xstart);
  470.  
  471.         putchar(c);
  472.         xpos++;
  473.  
  474.         if    (iskanji(c))
  475.         {
  476.             putchar(*p++);
  477.             xpos++;
  478.         }
  479.  
  480.         if    (xpos>=Window.xsize-1 || c=='\n')
  481.         {
  482.             ypos++;
  483.             xpos = 0;
  484.         }
  485.     }
  486. }
  487. /*-----------------------------文字列を入力する------------------------------*/
  488. /* 0<strlen(message)≦len≦CON_XWIDTH-5。ただしチェックはしない             */
  489. /*---------------------------------------------------------------------------*/
  490. extern    int    window_strinput(char *message,char *buf,unsigned len)
  491. {
  492.     int    f;
  493.  
  494.     openwindow(2,len+3);
  495.  
  496.     window_putstr(0,"%s",message);
  497.     window_putstr(1,"[%*s]",len,"");
  498.  
  499.     showcursor(1);
  500.     printf("\033[%d;%df",Window.ystart+1,Window.xstart+1);
  501.     f = ds_strinput(buf,len);
  502.     showcursor(0);
  503.  
  504.     closewindow();
  505.     return f;
  506. }
  507. /*---------------------選択肢を提示して入力を求める--------------------------*/
  508. /* messageは最大で64バイト×3行におさまること。ただしチェックはしない        */
  509. /*---------------------------------------------------------------------------*/
  510. /* messageの後には、16個以下のconst char *が続く。たとえば"Abort"や"I:中止"の*/
  511. /* ように、先頭の1バイトは入力する際の文字ともなる。なお1行に収まるようにする*/
  512. /* こと                                                                      */
  513. /*---------------------------------------------------------------------------*/
  514. extern    int    window_select(char *message,...)
  515. {
  516.     char    letter[16];
  517.     char    buf[256];
  518.     char    *p;
  519.     int    n=0;
  520.     va_list    ap;
  521.  
  522.     va_start(ap,message);
  523.  
  524.     openwindow(4,64);
  525.     window_putstr(0,"%s",message);
  526.  
  527.     buf[0] = '\0';
  528.  
  529.     while    ((p=va_arg(ap,char *))!=NULL)
  530.     {
  531.         strcat(buf,p);
  532.         strcat(buf,"     ");
  533.         letter[n++] = toupper(*p);
  534.     }
  535.  
  536.     va_end(ap);
  537.     window_putstr(3,"%s",buf);
  538.  
  539.     while    (1)
  540.     {
  541.         int    c = ds_getch();
  542.         int    i;
  543.  
  544.         if    (c>=0x100)
  545.             continue;
  546.  
  547.         c = toupper(c);
  548.  
  549.         for    (i=0 ; i<n ; i++)
  550.         {
  551.             if    (letter[i]==c)
  552.             {
  553.                 closewindow();
  554.                 return c;
  555.             }
  556.         }
  557.     }
  558. }
  559.  
  560. /*===========================================================================*/
  561. /*                               各種コマンド                                */
  562. /*===========================================================================*/
  563.  
  564. /*-------------------印刷(厳密には他のファイルへの出力)----------------------*/
  565. static    void    printout(void)
  566. {
  567.     static    char    filename[128] = "\\dev\\prn";
  568.     char    buf[128];
  569.     FILE    *fp;
  570.     int    i;
  571.  
  572.     strcpy(buf,filename);
  573.     if    (!window_strinput("印刷します 出力先デバイスを指定してください",buf,64))
  574.         return;
  575.  
  576.     strcpy(filename,buf);
  577.  
  578.     openwindow(2,64);
  579.  
  580.     fp = fopen(filename,"w");
  581.     if    (fp==NULL)
  582.     {
  583.         window_putstr(0,"%sがオープンできません",filename);
  584.         closewindow();
  585.         return;
  586.     }
  587.  
  588.     for    (i=0 ; i<Linenum ; i++)
  589.     {
  590.         if    (i%64==0)
  591.             window_putstr(0,"出力中 %d/%d",i,Linenum);
  592.  
  593.             /* 中止の確認はint24Hハンドラがやってくれているはず */
  594.         if    (far_fputs(Text[i],fp))
  595.         {
  596.             window_putstr(0,"中止しました");
  597.             goto error;
  598.         }
  599.     }
  600.  
  601.     window_putstr(0,"終了しました");
  602. error:
  603.     ds_getch();
  604.     closewindow();
  605.     fclose(fp);
  606. }
  607. /*------------------------------ヘルプの出力---------------------------------*/
  608. static    void    helpmessage(void)
  609. {
  610.     int    i;
  611.  
  612.     static    char    *message[] =
  613.     {
  614.         "[↑][↓]   スクロール",
  615.         "[F1]       概要ファイル/マニュアル切り替え",
  616.         "[F2]       現在見ているファイルの印刷",
  617.         "[F3]       インストール",
  618.         "[F4]       DOSコマンドライン",
  619.         "[F5]       ヘルプ(この画面)",
  620.         "[ESC][F10] 終了",
  621.     };
  622.  
  623.     openwindow(MEMBERSOF(message),64);
  624.  
  625.     for    (i=0 ; i<MEMBERSOF(message) ; i++)
  626.         window_putstr(i,message[i]);
  627.  
  628.     ds_getch();
  629.     closewindow();
  630. }
  631.  
  632. /*===========================================================================*/
  633. /*                     テキストビュワーのメインルーチン                      */
  634. /*===========================================================================*/
  635. extern    void    textviewer(struct DATA far *data)
  636. {
  637.     char    filename[2][256];    /* GGG/MANのファイル名 */
  638.     bool    ismanual = 0;
  639.  
  640.     if    (data->readme!=NULL)
  641.         mkpath(filename[0],data->dir,data->readme);
  642.     else if    (findfile(data->dir,"*.ggg"  ,filename[0]))    ;
  643.     else if    (findfile(data->dir,"!*.*"   ,filename[0]))    ;
  644.     else if    (findfile(data->dir,"read*.*",filename[0]))    ;
  645.     else if    (findfile(data->dir,"*.doc"  ,filename[0]))    ;
  646.  
  647.     if    (data->manual!=NULL)
  648.         mkpath(filename[1],data->dir,data->manual);
  649.     else if    (findfile(data->dir,"*.rrr",filename[1]))    ;
  650.     else if    (findfile(data->dir,"*.man",filename[1]))    ;
  651.     else if    (findfile(data->dir,"*.doc",filename[1]))    ;
  652.  
  653. again:
  654.     readfile(filename[ismanual]);
  655.     Linepos = 0;
  656.     screen_init(data->title,filename[ismanual]);
  657.  
  658.     while    (1)
  659.     {
  660.         switch    (ds_getch())
  661.         {
  662.         case FKEY_UP:
  663.             scrollup();
  664.             break;
  665.         case FKEY_DOWN:
  666.             scrolldown();
  667.             break;
  668.         case FKEY_LEFT:
  669.             if    ((Linepos-=TEXT_YWIDTH)<0)
  670.                 Linepos=0;
  671.             showtext();
  672.             break;
  673.         case FKEY_RIGHT:
  674.             if    ((Linepos+=TEXT_YWIDTH)>=Linenum)
  675.                 Linepos = Linenum-1;
  676.             showtext();
  677.             break;
  678.         case FKEY_F1:
  679.             ismanual = !ismanual;
  680.             memory_release();
  681.             goto again;
  682.         case FKEY_F2:
  683.             printout();
  684.             break;
  685.         case FKEY_F3:
  686.             installer(data);
  687.             break;
  688.         case FKEY_F4:
  689.             showcursor(1);
  690.             printf("\033[2J");
  691.             system("");
  692.             showcursor(0);
  693.             screen_init(NULL,NULL);
  694.             break;
  695.         case FKEY_F5:
  696.             helpmessage();
  697.             break;
  698.         case FKEY_F10:
  699.         case FKEY_ESC:
  700.             memory_release();
  701.             return;    /* 画面を元に戻すのは親関数の仕事 */
  702.         }
  703.     }
  704. }
  705. /*---------------------------End of textviewer.c-----------------------------*/
  706.